package com.example.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.domain.dto.RoleDTO;
import com.example.domain.entity.Menu;
import com.example.domain.entity.Role;
import com.example.domain.query.RoleQuery;
import com.example.domain.vo.MenuPermissionVO;
import com.example.mapper.RoleMapper;
import com.example.service.MenuService;
import com.example.service.RoleService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {

    private final RoleMapper roleMapper;
    private final MenuService menuService;

    @Override
    public IPage<Role> getRolePage(RoleQuery query) {
        return lambdaQuery()
                .and(StringUtils.hasText(query.getKeyword()), q -> q
                        .like(Role::getName, query.getKeyword())
                        .or()
                        .like(Role::getCode, query.getKeyword())
                )
                .eq(StringUtils.hasText(query.getStatus()), Role::getStatus, query.getStatus())
                .orderByAsc(Role::getSort)
                .page(new Page<>(query.getPageNum(), query.getPageSize()));
    }

    @Override
    public Role getRoleById(Long id) {
        Role role = getById(id);
        if (role != null) {
            role.setMenuIds(roleMapper.selectRoleMenuIds(id));
        }
        return role;
    }

    @Override
    public void addRole(RoleDTO roleDTO) {
        // 检查角色名称是否已存在
        if (lambdaQuery().eq(Role::getName, roleDTO.getName()).exists()) {
            throw new com.example.common.exception.ServiceException("角色名称已存在");
        }
        // 检查角色编码是否已存在
        if (lambdaQuery().eq(Role::getCode, roleDTO.getCode()).exists()) {
            throw new com.example.common.exception.ServiceException("角色编码已存在");
        }

        Role role = new Role();
        BeanUtils.copyProperties(roleDTO, role);

        // 保存角色
        save(role);

        // 保存角色菜单关联
        if (roleDTO.getMenuIds() != null && !roleDTO.getMenuIds().isEmpty()) {
            roleMapper.insertRoleMenus(role.getId(), roleDTO.getMenuIds());
        }
    }

    @Override
    public void updateRole(RoleDTO roleDTO) {
        Role role = getById(roleDTO.getId());
        if (role == null) {
            throw new com.example.common.exception.ServiceException("角色不存在");
        }

        // 如果修改了角色名称，检查是否已存在
        if (!role.getName().equals(roleDTO.getName())) {
            if (lambdaQuery().eq(Role::getName, roleDTO.getName()).exists()) {
                throw new com.example.common.exception.ServiceException("角色名称已存在");
            }
        }

        // 如果修改了角色编码，检查是否已存在
        if (!role.getCode().equals(roleDTO.getCode())) {
            if (lambdaQuery().eq(Role::getCode, roleDTO.getCode()).exists()) {
                throw new com.example.common.exception.ServiceException("角色编码已存在");
            }
        }

        BeanUtils.copyProperties(roleDTO, role);

        // 更新角色
        updateById(role);

        // 更新角色菜单关联
        roleMapper.deleteRoleMenus(role.getId());
        if (roleDTO.getMenuIds() != null && !roleDTO.getMenuIds().isEmpty()) {
            roleMapper.insertRoleMenus(role.getId(), roleDTO.getMenuIds());
        }
    }

    @Override
    public void deleteRole(Long id) {
        // 删除角色菜单关联
        roleMapper.deleteRoleMenus(id);
        // 删除角色
        removeById(id);
    }

    @Override
    public void batchDeleteRole(List<Long> ids) {
        // 删除角色菜单关联
        roleMapper.deleteRoleMenusByRoleIds(ids);
        // 删除角色
        removeBatchByIds(ids);
    }

    @Override
    public List<Long> getRoleMenuIds(Long roleId) {
        return roleMapper.selectRoleMenuIds(roleId);
    }

    @Override
    public void assignMenus(Long roleId, List<Long> menuIds) {
        // 删除原有关联
        roleMapper.deleteRoleMenus(roleId);
        // 添加新的关联
        if (menuIds != null && !menuIds.isEmpty()) {
            roleMapper.insertRoleMenus(roleId, menuIds);
        }
    }

    @Override
    public List<Role> getAllRoles() {
        return lambdaQuery()
                .eq(Role::getStatus, "1")
                .orderByAsc(Role::getSort)
                .list();
    }

    @Override
    public List<MenuPermissionVO> getRoleMenuPermissions(Long roleId) {
        // 获取所有菜单
        List<Menu> allMenus = menuService.list(new LambdaQueryWrapper<Menu>()
                .eq(Menu::getStatus, "1")
                .orderByAsc(Menu::getSort));
        
        // 获取角色已选择的菜单ID
        List<Long> checkedMenuIds = roleMapper.selectRoleMenuIds(roleId);
        
        // 构建树形结构
        return buildMenuPermissionTree(allMenus, checkedMenuIds, 0L);
    }

    private List<MenuPermissionVO> buildMenuPermissionTree(List<Menu> allMenus, List<Long> checkedMenuIds, Long parentId) {
        return allMenus.stream()
                .filter(menu -> menu.getParentId().equals(parentId))
                .map(menu -> {
                    MenuPermissionVO vo = new MenuPermissionVO();
                    vo.setId(menu.getId());
                    vo.setTitle(menu.getTitle());
                    
                    // 递归获取子节点
                    List<MenuPermissionVO> children = buildMenuPermissionTree(allMenus, checkedMenuIds, menu.getId());
                    vo.setChildren(children);
                    
                    // 计算选中状态
                    if (children.isEmpty()) {
                        // 叶子节点
                        vo.setChecked(checkedMenuIds.contains(menu.getId()));
                        vo.setHalfChecked(false);
                    } else {
                        // 非叶子节点
                        long checkedCount = children.stream()
                                .filter(MenuPermissionVO::getChecked)
                                .count();
                        long halfCheckedCount = children.stream()
                                .filter(MenuPermissionVO::getHalfChecked)
                                .count();
                        
                        // 全部子节点选中
                        if (checkedCount == children.size()) {
                            vo.setChecked(true);
                            vo.setHalfChecked(false);
                        }
                        // 部分子节点选中或半选
                        else if (checkedCount > 0 || halfCheckedCount > 0) {
                            vo.setChecked(false);
                            vo.setHalfChecked(true);
                        }
                        // 没有子节点选中
                        else {
                            vo.setChecked(false);
                            vo.setHalfChecked(false);
                        }
                    }
                    
                    return vo;
                })
                .collect(Collectors.toList());
    }
} 